package com.reservation.service;

import com.reservation.dto.ProductDTO;
import com.reservation.entity.Product;
import com.reservation.repository.ProductRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 商品服务类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ProductService {

    private final ProductRepository productRepository;

    /**
     * 获取所有商品
     */
    public List<ProductDTO> getAllProducts() {
        log.info("获取所有商品列表");
        List<Product> products = productRepository.findByIsActiveTrueOrderByIdAsc();
        return products.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    /**
     * 获取有库存的商品
     */
    public List<ProductDTO> getAvailableProducts() {
        log.info("获取有库存的商品列表");
        List<Product> products = productRepository.findAvailableProducts();
        return products.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    /**
     * 根据ID获取商品
     */
    public Optional<ProductDTO> getProductById(Long id) {
        log.info("根据ID获取商品: {}", id);
        return productRepository.findByIdAndIsActiveTrue(id)
                .map(this::convertToDTO);
    }

    /**
     * 根据名称搜索商品
     */
    public List<ProductDTO> searchProductsByName(String name) {
        log.info("根据名称搜索商品: {}", name);
        List<Product> products = productRepository.findByNameContainingIgnoreCaseAndIsActiveTrueOrderByIdAsc(name);
        return products.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    /**
     * 减少商品库存
     */
    @Transactional
    public void decreaseStock(Long productId, Integer quantity) {
        log.info("减少商品库存: productId={}, quantity={}", productId, quantity);
        Product product = productRepository.findById(productId)
                .orElseThrow(() -> new RuntimeException("商品不存在"));
        
        if (!product.hasEnoughStock(quantity)) {
            throw new RuntimeException("库存不足");
        }
        
        product.decreaseStock(quantity);
        productRepository.save(product);
        log.info("商品库存减少成功: productId={}, 剩余库存={}", productId, product.getStock());
    }

    /**
     * 增加商品库存
     */
    @Transactional
    public void increaseStock(Long productId, Integer quantity) {
        log.info("增加商品库存: productId={}, quantity={}", productId, quantity);
        Product product = productRepository.findById(productId)
                .orElseThrow(() -> new RuntimeException("商品不存在"));
        
        product.increaseStock(quantity);
        productRepository.save(product);
        log.info("商品库存增加成功: productId={}, 当前库存={}", productId, product.getStock());
    }

    /**
     * 检查库存是否充足
     */
    public boolean checkStock(Long productId, Integer quantity) {
        Product product = productRepository.findById(productId)
                .orElseThrow(() -> new RuntimeException("商品不存在"));
        return product.hasEnoughStock(quantity);
    }

    /**
     * 获取库存不足的商品
     */
    public List<ProductDTO> getLowStockProducts(Integer threshold) {
        log.info("获取库存不足的商品: threshold={}", threshold);
        List<Product> products = productRepository.findLowStockProducts(threshold);
        return products.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    /**
     * 转换为DTO
     */
    private ProductDTO convertToDTO(Product product) {
        ProductDTO dto = new ProductDTO();
        dto.setId(product.getId());
        dto.setName(product.getName());
        dto.setPrice(product.getPrice());
        dto.setImage(product.getImage());
        dto.setStock(product.getStock());
        dto.setDescription(product.getDescription());
        dto.setIsActive(product.getIsActive());
        dto.setCreatedAt(product.getCreatedAt());
        dto.setUpdatedAt(product.getUpdatedAt());
        return dto;
    }
}
